/*
	JCZSolve - Sudoku Solver by JasonLion based on champagne's version of the zhouyundong_2012's solver

	Based on code posted to:
		<http://forum.enjoysudoku.com/3-77us-solver-2-8g-cpu-testcase-17sodoku-t30470.html>
	by user zhouyundong_2012.
	Key insights include storing bands by digit and the Update routine
	The copyright is not specified.

	Subsequently updated by user champagne for 128 bit registers and speed optimization.
	Key insights include the pairing of ApplySingleOrEmptyCells and GuessBiValueInCell
	The copyright is not specified.

	Converted back to 32 bit data with further speed optimizations by JasonLion.
	The copyright is not specified.
*/

#include <stdio.h>
#include <string.h>
#include <ctype.h>

typedef struct state {
	unsigned int bands[9*3];				// Pencil marks in bands by digit
	unsigned int prevBands[9*3];			// Value of bands last time it was calculated
	unsigned int unsolvedCells[3];			// Bit vector of unsolved cells
	unsigned int unsolvedRows[3];			// Bit vector of unsolved rows - three bits per band
	unsigned int pairs[3];					// Bit vector of cells with exactly two pencil marks
	} State;

static State stack[50];						// Stack to store current and previous states
static State *g;							// Pointer to the currently active slot
static int numSolutions;					// The number of solutions found so far
static int limitSolutions;					// The max number of solution we are looking for
static int singleApplied;					// Nasty global flag telling if ApplySingleOrEmptyCells found anything
static char *solution;						// Pointer to where to store the first solution, can be null


extern size_t JCZSolve_guesses;

#define BIT_SET_27         0777777777		// all pencil marks set - 27 bits per band

static const int TblShrinkMask[512] = {
	0, 1, 1, 1, 1, 1, 1, 1, 2, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3,
	2, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3,
	4, 5, 5, 5, 5, 5, 5, 5, 6, 7, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7, 7, 7, 7, 7,
	6, 7, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7, 7, 7, 7, 7,
	4, 5, 5, 5, 5, 5, 5, 5, 6, 7, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7, 7, 7, 7, 7,
	6, 7, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7, 7, 7, 7, 7,
	4, 5, 5, 5, 5, 5, 5, 5, 6, 7, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7, 7, 7, 7, 7,
	6, 7, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7, 7, 7, 7, 7,
	4, 5, 5, 5, 5, 5, 5, 5, 6, 7, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7, 7, 7, 7, 7,
	6, 7, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7, 7, 7, 7, 7,
	4, 5, 5, 5, 5, 5, 5, 5, 6, 7, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7, 7, 7, 7, 7,
	6, 7, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7, 7, 7, 7, 7,
	4, 5, 5, 5, 5, 5, 5, 5, 6, 7, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7, 7, 7, 7, 7,
	6, 7, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7, 7, 7, 7, 7,
	4, 5, 5, 5, 5, 5, 5, 5, 6, 7, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7, 7, 7, 7, 7,
	6, 7, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7, 7, 7, 7, 7, 6, 7, 7, 7, 7, 7, 7, 7,
	};

static const unsigned int TblComplexMask[512] = {	// keep mini rows still valid
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 07007070700, 07707070700, 07007770700, 07707770700,
	0, 0, 0, 0, 07077070700, 07777070700, 07777770700, 07777770700,
	0, 0, 07007700070, 07077700070, 0, 0, 07007770070, 07077770070,
	0, 0, 07707700070, 07777700070, 0, 0, 07777770070, 07777770070,
	0, 0, 07007700770, 07777700770, 07007070770, 07777070770, 07007770770, 07777770770,
	0, 0, 07707700770, 07777700770, 07077070770, 07777070770, 07777770770, 07777770770,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 07070007700, 07070707700, 07770007700, 07770707700,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 07077007700, 07777707700, 07777007700, 07777707700,
	0, 07070700007, 0, 07077700007, 0, 07070707007, 0, 07077707007,
	0, 07070700707, 0, 07777700707, 07070007707, 07070707707, 07777007707, 07777707707,
	0, 07770700007, 0, 07777700007, 0, 07777707007, 0, 07777707007,
	0, 07770700707, 0, 07777700707, 07077007707, 07777707707, 07777007707, 07777707707,
	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 07070077700, 07070777700, 07770777700, 07770777700,
	0, 0, 0, 0, 07007077700, 07707777700, 07007777700, 07707777700,
	0, 0, 0, 0, 07077077700, 07777777700, 07777777700, 07777777700,
	0, 07070700077, 07007700077, 07077700077, 0, 07070777077, 07007777077, 07077777077,
	0, 07070700777, 07707700777, 07777700777, 07070077777, 07070777777, 07777777777, 07777777777,
	0, 07770700777, 07007700777, 07777700777, 07007077777, 07777777777, 07007777777, 07777777777,
	0, 07770700777, 07707700777, 07777700777, 07077077777, 07777777777, 07777777777, 07777777777,
	0, 0, 0, 0, 0, 0, 0, 0,
	00, 0, 07700007070, 07700077070, 0, 0, 07770007070, 07770077070,
	00, 07700070007, 0, 07700077007, 0, 07707070007, 0, 07707077007,
	00, 07700070077, 07700007077, 07700077077, 0, 07777070077, 07777007077, 07777077077,
	00, 0, 0, 0, 0, 0, 0, 0,
	00, 0, 07707007070, 07777077070, 0, 0, 07777007070, 07777077070,
	00, 07770070007, 0, 07777077007, 0, 07777070007, 0, 07777077007,
	00, 07770070077, 07707007077, 07777077077, 0, 07777070077, 07777007077, 07777077077,
	00, 0, 0, 0, 0, 0, 0, 0,
	00, 0, 07700707070, 07700777070, 0, 0, 07770777070, 07770777070,
	00, 07700070707, 0, 07700777707, 07007070707, 07707070707, 07007777707, 07707777707,
	00, 07700070777, 07700707777, 07700777777, 07077070777, 07777070777, 07777777777, 07777777777,
	00, 0, 07007707070, 07077777070, 0, 0, 07007777070, 07077777070,
	00, 0, 07707707070, 07777777070, 0, 0, 07777777070, 07777777070,
	00, 07770070777, 07007707777, 07777777777, 07007070777, 07777070777, 07007777777, 07777777777,
	00, 07770070777, 07707707777, 07777777777, 07077070777, 07777070777, 07777777777, 07777777777,
	00, 0, 0, 0, 0, 0, 0, 0,
	00, 0, 07700007770, 07700777770, 07070007770, 07070777770, 07770007770, 07770777770,
	00, 07700770007, 0, 07700777007, 0, 07707777007, 0, 07707777007,
	00, 07700770777, 07700007777, 07700777777, 07077007777, 07777777777, 07777007777, 07777777777,
	00, 07070770007, 0, 07077777007, 0, 07070777007, 0, 07077777007,
	00, 07070770777, 07707007777, 07777777777, 07070007777, 07070777777, 07777007777, 07777777777,
	00, 07770770007, 0, 07777777007, 0, 07777777007, 0, 07777777007,
	00, 07770770777, 07707007777, 07777777777, 07077007777, 07777777777, 07777007777, 07777777777,
	00, 0, 0, 0, 0, 0, 0, 0,
	00, 0, 07700707770, 07700777770, 07070077770, 07070777770, 07770777770, 07770777770,
	00, 07700770707, 0, 07700777707, 07007077707, 07707777707, 07007777707, 07707777707,
	00, 07700770777, 07700707777, 07700777777, 07077077777, 07777777777, 07777777777, 07777777777,
	00, 07070770077, 07007707077, 07077777077, 0, 07070777077, 07007777077, 07077777077,
	00, 07070770777, 07707707777, 07777777777, 07070077777, 07070777777, 07777777777, 07777777777,
	00, 07770770777, 07007707777, 07777777777, 07007077777, 07777777777, 07007777777, 07777777777,
	00, 07770770777, 07707707777, 07777777777, 07077077777, 07777777777, 07777777777, 07777777777,
	};

static const unsigned int TblMaskSingle[512] = {	// kill in other blocks locked column /box
	07777777777, 07776776776, 07775775775, 07777777777, 07773773773, 07777777777, 07777777777, 07777777777,
	07767767767, 07766766766, 07765765765, 07767767767, 07763763763, 07767767767, 07767767767, 07767767767,
	07757757757, 07756756756, 07755755755, 07757757757, 07753753753, 07757757757, 07757757757, 07757757757,
	07777777777, 07776776776, 07775775775, 07777777777, 07773773773, 07777777777, 07777777777, 07777777777,
	07737737737, 07736736736, 07735735735, 07737737737, 07733733733, 07737737737, 07737737737, 07737737737,
	07777777777, 07776776776, 07775775775, 07777777777, 07773773773, 07777777777, 07777777777, 07777777777,
	07777777777, 07776776776, 07775775775, 07777777777, 07773773773, 07777777777, 07777777777, 07777777777,
	07777777777, 07776776776, 07775775775, 07777777777, 07773773773, 07777777777, 07777777777, 07777777777,
	07677677677, 07676676676, 07675675675, 07677677677, 07673673673, 07677677677, 07677677677, 07677677677,
	07667667667, 07666666666, 07665665665, 07667667667, 07663663663, 07667667667, 07667667667, 07667667667,
	07657657657, 07656656656, 07655655655, 07657657657, 07653653653, 07657657657, 07657657657, 07657657657,
	07677677677, 07676676676, 07675675675, 07677677677, 07673673673, 07677677677, 07677677677, 07677677677,
	07637637637, 07636636636, 07635635635, 07637637637, 07633633633, 07637637637, 07637637637, 07637637637,
	07677677677, 07676676676, 07675675675, 07677677677, 07673673673, 07677677677, 07677677677, 07677677677,
	07677677677, 07676676676, 07675675675, 07677677677, 07673673673, 07677677677, 07677677677, 07677677677,
	07677677677, 07676676676, 07675675675, 07677677677, 07673673673, 07677677677, 07677677677, 07677677677,
	07577577577, 07576576576, 07575575575, 07577577577, 07573573573, 07577577577, 07577577577, 07577577577,
	07567567567, 07566566566, 07565565565, 07567567567, 07563563563, 07567567567, 07567567567, 07567567567,
	07557557557, 07556556556, 07555555555, 07557557557, 07553553553, 07557557557, 07557557557, 07557557557,
	07577577577, 07576576576, 07575575575, 07577577577, 07573573573, 07577577577, 07577577577, 07577577577,
	07537537537, 07536536536, 07535535535, 07537537537, 07533533533, 07537537537, 07537537537, 07537537537,
	07577577577, 07576576576, 07575575575, 07577577577, 07573573573, 07577577577, 07577577577, 07577577577,
	07577577577, 07576576576, 07575575575, 07577577577, 07573573573, 07577577577, 07577577577, 07577577577,
	07577577577, 07576576576, 07575575575, 07577577577, 07573573573, 07577577577, 07577577577, 07577577577,
	07777777777, 07776776776, 07775775775, 07777777777, 07773773773, 07777777777, 07777777777, 07777777777,
	07767767767, 07766766766, 07765765765, 07767767767, 07763763763, 07767767767, 07767767767, 07767767767,
	07757757757, 07756756756, 07755755755, 07757757757, 07753753753, 07757757757, 07757757757, 07757757757,
	07777777777, 07776776776, 07775775775, 07777777777, 07773773773, 07777777777, 07777777777, 07777777777,
	07737737737, 07736736736, 07735735735, 07737737737, 07733733733, 07737737737, 07737737737, 07737737737,
	07777777777, 07776776776, 07775775775, 07777777777, 07773773773, 07777777777, 07777777777, 07777777777,
	07777777777, 07776776776, 07775775775, 07777777777, 07773773773, 07777777777, 07777777777, 07777777777,
	07777777777, 07776776776, 07775775775, 07777777777, 07773773773, 07777777777, 07777777777, 07777777777,
	07377377377, 07376376376, 07375375375, 07377377377, 07373373373, 07377377377, 07377377377, 07377377377,
	07367367367, 07366366366, 07365365365, 07367367367, 07363363363, 07367367367, 07367367367, 07367367367,
	07357357357, 07356356356, 07355355355, 07357357357, 07353353353, 07357357357, 07357357357, 07357357357,
	07377377377, 07376376376, 07375375375, 07377377377, 07373373373, 07377377377, 07377377377, 07377377377,
	07337337337, 07336336336, 07335335335, 07337337337, 07333333333, 07337337337, 07337337337, 07337337337,
	07377377377, 07376376376, 07375375375, 07377377377, 07373373373, 07377377377, 07377377377, 07377377377,
	07377377377, 07376376376, 07375375375, 07377377377, 07373373373, 07377377377, 07377377377, 07377377377,
	07377377377, 07376376376, 07375375375, 07377377377, 07373373373, 07377377377, 07377377377, 07377377377,
	07777777777, 07776776776, 07775775775, 07777777777, 07773773773, 07777777777, 07777777777, 07777777777,
	07767767767, 07766766766, 07765765765, 07767767767, 07763763763, 07767767767, 07767767767, 07767767767,
	07757757757, 07756756756, 07755755755, 07757757757, 07753753753, 07757757757, 07757757757, 07757757757,
	07777777777, 07776776776, 07775775775, 07777777777, 07773773773, 07777777777, 07777777777, 07777777777,
	07737737737, 07736736736, 07735735735, 07737737737, 07733733733, 07737737737, 07737737737, 07737737737,
	07777777777, 07776776776, 07775775775, 07777777777, 07773773773, 07777777777, 07777777777, 07777777777,
	07777777777, 07776776776, 07775775775, 07777777777, 07773773773, 07777777777, 07777777777, 07777777777,
	07777777777, 07776776776, 07775775775, 07777777777, 07773773773, 07777777777, 07777777777, 07777777777,
	07777777777, 07776776776, 07775775775, 07777777777, 07773773773, 07777777777, 07777777777, 07777777777,
	07767767767, 07766766766, 07765765765, 07767767767, 07763763763, 07767767767, 07767767767, 07767767767,
	07757757757, 07756756756, 07755755755, 07757757757, 07753753753, 07757757757, 07757757757, 07757757757,
	07777777777, 07776776776, 07775775775, 07777777777, 07773773773, 07777777777, 07777777777, 07777777777,
	07737737737, 07736736736, 07735735735, 07737737737, 07733733733, 07737737737, 07737737737, 07737737737,
	07777777777, 07776776776, 07775775775, 07777777777, 07773773773, 07777777777, 07777777777, 07777777777,
	07777777777, 07776776776, 07775775775, 07777777777, 07773773773, 07777777777, 07777777777, 07777777777,
	07777777777, 07776776776, 07775775775, 07777777777, 07773773773, 07777777777, 07777777777, 07777777777,
	07777777777, 07776776776, 07775775775, 07777777777, 07773773773, 07777777777, 07777777777, 07777777777,
	07767767767, 07766766766, 07765765765, 07767767767, 07763763763, 07767767767, 07767767767, 07767767767,
	07757757757, 07756756756, 07755755755, 07757757757, 07753753753, 07757757757, 07757757757, 07757757757,
	07777777777, 07776776776, 07775775775, 07777777777, 07773773773, 07777777777, 07777777777, 07777777777,
	07737737737, 07736736736, 07735735735, 07737737737, 07733733733, 07737737737, 07737737737, 07737737737,
	07777777777, 07776776776, 07775775775, 07777777777, 07773773773, 07777777777, 07777777777, 07777777777,
	07777777777, 07776776776, 07775775775, 07777777777, 07773773773, 07777777777, 07777777777, 07777777777,
	07777777777, 07776776776, 07775775775, 07777777777, 07773773773, 07777777777, 07777777777, 07777777777,
	};

#if 0
#if 1
static const unsigned int TblMaskDouble[512] = {	// kill for locked in box / column
	07777777777, 07777777777, 07777777777, 07774774774, 07777777777, 07772772772, 07771771771, 07777777777,
	07777777777, 07777777777, 07777777777, 07774774774, 07777777777, 07772772772, 07771771771, 07777777777,
	07777777777, 07777777777, 07777777777, 07774774774, 07777777777, 07772772772, 07771771771, 07777777777,
	07747747747, 07747747747, 07747747747, 07744744744, 07747747747, 07742742742, 07741741741, 07747747747,
	07777777777, 07777777777, 07777777777, 07774774774, 07777777777, 07772772772, 07771771771, 07777777777,
	07727727727, 07727727727, 07727727727, 07724724724, 07727727727, 07722722722, 07721721721, 07727727727,
	07717717717, 07717717717, 07717717717, 07714714714, 07717717717, 07712712712, 07711711711, 07717717717,
	07777777777, 07777777777, 07777777777, 07774774774, 07777777777, 07772772772, 07771771771, 07777777777,
	07777777777, 07777777777, 07777777777, 07774774774, 07777777777, 07772772772, 07771771771, 07777777777,
	07777777777, 07777777777, 07777777777, 07774774774, 07777777777, 07772772772, 07771771771, 07777777777,
	07777777777, 07777777777, 07777777777, 07774774774, 07777777777, 07772772772, 07771771771, 07777777777,
	07747747747, 07747747747, 07747747747, 07744744744, 07747747747, 07742742742, 07741741741, 07747747747,
	07777777777, 07777777777, 07777777777, 07774774774, 07777777777, 07772772772, 07771771771, 07777777777,
	07727727727, 07727727727, 07727727727, 07724724724, 07727727727, 07722722722, 07721721721, 07727727727,
	07717717717, 07717717717, 07717717717, 07714714714, 07717717717, 07712712712, 07711711711, 07717717717,
	07777777777, 07777777777, 07777777777, 07774774774, 07777777777, 07772772772, 07771771771, 07777777777,
	07777777777, 07777777777, 07777777777, 07774774774, 07777777777, 07772772772, 07771771771, 07777777777,
	07777777777, 07777777777, 07777777777, 07774774774, 07777777777, 07772772772, 07771771771, 07777777777,
	07777777777, 07777777777, 07777777777, 07774774774, 07777777777, 07772772772, 07771771771, 07777777777,
	07747747747, 07747747747, 07747747747, 07744744744, 07747747747, 07742742742, 07741741741, 07747747747,
	07777777777, 07777777777, 07777777777, 07774774774, 07777777777, 07772772772, 07771771771, 07777777777,
	07727727727, 07727727727, 07727727727, 07724724724, 07727727727, 07722722722, 07721721721, 07727727727,
	07717717717, 07717717717, 07717717717, 07714714714, 07717717717, 07712712712, 07711711711, 07717717717,
	07777777777, 07777777777, 07777777777, 07774774774, 07777777777, 07772772772, 07771771771, 07777777777,
	07477477477, 07477477477, 07477477477, 07474474474, 07477477477, 07472472472, 07471471471, 07477477477,
	07477477477, 07477477477, 07477477477, 07474474474, 07477477477, 07472472472, 07471471471, 07477477477,
	07477477477, 07477477477, 07477477477, 07474474474, 07477477477, 07472472472, 07471471471, 07477477477,
	07447447447, 07447447447, 07447447447, 07444444444, 07447447447, 07442442442, 07441441441, 07447447447,
	07477477477, 07477477477, 07477477477, 07474474474, 07477477477, 07472472472, 07471471471, 07477477477,
	07427427427, 07427427427, 07427427427, 07424424424, 07427427427, 07422422422, 07421421421, 07427427427,
	07417417417, 07417417417, 07417417417, 07414414414, 07417417417, 07412412412, 07411411411, 07417417417,
	07477477477, 07477477477, 07477477477, 07474474474, 07477477477, 07472472472, 07471471471, 07477477477,
	07777777777, 07777777777, 07777777777, 07774774774, 07777777777, 07772772772, 07771771771, 07777777777,
	07777777777, 07777777777, 07777777777, 07774774774, 07777777777, 07772772772, 07771771771, 07777777777,
	07777777777, 07777777777, 07777777777, 07774774774, 07777777777, 07772772772, 07771771771, 07777777777,
	07747747747, 07747747747, 07747747747, 07744744744, 07747747747, 07742742742, 07741741741, 07747747747,
	07777777777, 07777777777, 07777777777, 07774774774, 07777777777, 07772772772, 07771771771, 07777777777,
	07727727727, 07727727727, 07727727727, 07724724724, 07727727727, 07722722722, 07721721721, 07727727727,
	07717717717, 07717717717, 07717717717, 07714714714, 07717717717, 07712712712, 07711711711, 07717717717,
	07777777777, 07777777777, 07777777777, 07774774774, 07777777777, 07772772772, 07771771771, 07777777777,
	07277277277, 07277277277, 07277277277, 07274274274, 07277277277, 07272272272, 07271271271, 07277277277,
	07277277277, 07277277277, 07277277277, 07274274274, 07277277277, 07272272272, 07271271271, 07277277277,
	07277277277, 07277277277, 07277277277, 07274274274, 07277277277, 07272272272, 07271271271, 07277277277,
	07247247247, 07247247247, 07247247247, 07244244244, 07247247247, 07242242242, 07241241241, 07247247247,
	07277277277, 07277277277, 07277277277, 07274274274, 07277277277, 07272272272, 07271271271, 07277277277,
	07227227227, 07227227227, 07227227227, 07224224224, 07227227227, 07222222222, 07221221221, 07227227227,
	07217217217, 07217217217, 07217217217, 07214214214, 07217217217, 07212212212, 07211211211, 07217217217,
	07277277277, 07277277277, 07277277277, 07274274274, 07277277277, 07272272272, 07271271271, 07277277277,
	07177177177, 07177177177, 07177177177, 07174174174, 07177177177, 07172172172, 07171171171, 07177177177,
	07177177177, 07177177177, 07177177177, 07174174174, 07177177177, 07172172172, 07171171171, 07177177177,
	07177177177, 07177177177, 07177177177, 07174174174, 07177177177, 07172172172, 07171171171, 07177177177,
	07147147147, 07147147147, 07147147147, 07144144144, 07147147147, 07142142142, 07141141141, 07147147147,
	07177177177, 07177177177, 07177177177, 07174174174, 07177177177, 07172172172, 07171171171, 07177177177,
	07127127127, 07127127127, 07127127127, 07124124124, 07127127127, 07122122122, 07121121121, 07127127127,
	07117117117, 07117117117, 07117117117, 07114114114, 07117117117, 07112112112, 07111111111, 07117117117,
	07177177177, 07177177177, 07177177177, 07174174174, 07177177177, 07172172172, 07171171171, 07177177177,
	07777777777, 07777777777, 07777777777, 07774774774, 07777777777, 07772772772, 07771771771, 07777777777,
	07777777777, 07777777777, 07777777777, 07774774774, 07777777777, 07772772772, 07771771771, 07777777777,
	07777777777, 07777777777, 07777777777, 07774774774, 07777777777, 07772772772, 07771771771, 07777777777,
	07747747747, 07747747747, 07747747747, 07744744744, 07747747747, 07742742742, 07741741741, 07747747747,
	07777777777, 07777777777, 07777777777, 07774774774, 07777777777, 07772772772, 07771771771, 07777777777,
	07727727727, 07727727727, 07727727727, 07724724724, 07727727727, 07722722722, 07721721721, 07727727727,
	07717717717, 07717717717, 07717717717, 07714714714, 07717717717, 07712712712, 07711711711, 07717717717,
	07777777777, 07777777777, 07777777777, 07774774774, 07777777777, 07772772772, 07771771771, 07777777777,
	};
#else
static const unsigned int TblMaskDouble[512] = {	// kill for locked in box / column
	00,	00,	00,	00,	00,	00,	00,	00,
	00,	00,	00,	00,	00,	00,	00,	00,
	00,	00,	00,	00,	00,	00,	00,	00,
	00,	00,	00,	00,	00,	00,	00,	00,
	00,	00,	00,	00,	00,	00,	00,	00,
	00,	00,	00,	00,	00,	00,	00,	00,
	00,	00,	00,	00,	00,	00,	00,	00,
	00,	00,	00,	00,	00,	00,	00,	00,
	00,	00,	00,	00,	00,	00,	00,	00,
	00,	00,	00,	00,	00,	00,	00,	00,
	00,	00,	00,	00,	00,	00,	00,	00,
	00,	00,	00,	00,	00,	00,	00,	00,
	00,	00,	00,	00,	00,	00,	00,	00,
	00,	00,	00,	00,	00,	00,	00,	00,
	00,	00,	00,	00,	00,	00,	00,	00,
	00,	00,	00,	00,	00,	00,	00,	00,
	00,	00,	00,	00,	00,	00,	00,	00,
	00,	00,	00,	00,	00,	00,	00,	00,
	00,	00,	00,	00,	00,	00,	00,	00,
	00,	00,	00,	00,	00,	00,	00,	00,
	00,	00,	00,	00,	00,	00,	00,	00,
	00,	00,	00,	00,	00,	00,	00,	00,
	00,	00,	00,	00,	00,	00,	00,	00,
	00,	00,	00,	00,	00,	00,	00,	00,
	00,	00,	00,	00,	00,	00,	00,	00,
	00,	00,	00,	00,	00,	00,	00,	00,
	00,	00,	00,	00,	00,	00,	00,	00,
	00,	00,	00,	0444444444,	00,	0442442442,	0441441441,	0447447447,
	00,	00,	00,	00,	00,	00,	00,	00,
	00,	00,	00,	0424424424,	00,	0422422422,	0421421421,	0427427427,
	00,	00,	00,	0414414414,	00,	0412412412,	0411411411,	0417417417,
	00,	00,	00,	0474474474,	00,	0472472472,	0471471471,	0477477477,
	00,	00,	00,	00,	00,	00,	00,	00,
	00,	00,	00,	00,	00,	00,	00,	00,
	00,	00,	00,	00,	00,	00,	00,	00,
	00,	00,	00,	00,	00,	00,	00,	00,
	00,	00,	00,	00,	00,	00,	00,	00,
	00,	00,	00,	00,	00,	00,	00,	00,
	00,	00,	00,	00,	00,	00,	00,	00,
	00,	00,	00,	00,	00,	00,	00,	00,
	00,	00,	00,	00,	00,	00,	00,	00,
	00,	00,	00,	00,	00,	00,	00,	00,
	00,	00,	00,	00,	00,	00,	00,	00,
	00,	00,	00,	0244244244,	00,	0242242242,	0241241241,	0247247247,
	00,	00,	00,	00,	00,	00,	00,	00,
	00,	00,	00,	0224224224,	00,	0222222222,	0221221221,	0227227227,
	00,	00,	00,	0214214214,	00,	0212212212,	0211211211,	0217217217,
	00,	00,	00,	0274274274,	00,	0272272272,	0271271271,	0277277277,
	00,	00,	00,	00,	00,	00,	00,	00,
	00,	00,	00,	00,	00,	00,	00,	00,
	00,	00,	00,	00,	00,	00,	00,	00,
	00,	00,	00,	0144144144,	00,	0142142142,	0141141141,	0147147147,
	00,	00,	00,	00,	00,	00,	00,	00,
	00,	00,	00,	0124124124,	00,	0122122122,	0121121121,	0127127127,
	00,	00,	00,	0114114114,	00,	0112112112,	0111111111,	0117117117,
	00,	00,	00,	0174174174,	00,	0172172172,	0171171171,	0177177177,
	00,	00,	00,	00,	00,	00,	00,	00,
	00,	00,	00,	00,	00,	00,	00,	00,
	00,	00,	00,	00,	00,	00,	00,	00,
	00,	00,	00,	0744744744,	00,	0742742742,	0741741741,	0747747747,
	00,	00,	00,	00,	00,	00,	00,	00,
	00,	00,	00,	0724724724,	00,	0722722722,	0721721721,	0727727727,
	00,	00,	00,	0714714714,	00,	0712712712,	0711711711,	0717717717,
	00,	00,	00,	0774774774,	00,	0772772772,	0771771771,	0777777777,
	};
#endif
#endif

static const int TblShrinkSingle[512] = {	// keep only rows with single
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0124, 0124, 0124, 0124, 0, 0, 0, 0, 0124, 0124, 0124, 0124,
	0, 0, 0142, 0142, 0, 0, 0142, 0142, 0, 0, 0142, 0142, 0, 0, 0142, 0142, 0, 0, 0142, 0142, 0124, 0124, 0100, 0100, 0, 0, 0142, 0142, 0124, 0124, 0100, 0100,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0214, 0214, 0214, 0214, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0214, 0214, 0214, 0214,
	0, 0241, 0, 0241, 0, 0241, 0, 0241, 0, 0241, 0, 0241, 0214, 0200, 0214, 0200, 0, 0241, 0, 0241, 0, 0241, 0, 0241, 0, 0241, 0, 0241, 0214, 0200, 0214, 0200,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0214, 0214, 0214, 0214, 0, 0, 0, 0, 0124, 0124, 0124, 0124, 0, 0, 0, 0, 04, 04, 04, 04,
	0, 0241, 0142, 040, 0, 0241, 0142, 040, 0, 0241, 0142, 040, 0214, 0200, 0, 0, 0, 0241, 0142, 040, 0124, 0, 0100, 0, 0, 0241, 0142, 040, 04, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0412, 0412, 0, 0, 0412, 0412, 0, 0421, 0, 0421, 0, 0421, 0, 0421, 0, 0421, 0412, 0400, 0, 0421, 0412, 0400,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0412, 0412, 0, 0, 0412, 0412, 0, 0421, 0, 0421, 0, 0421, 0, 0421, 0, 0421, 0412, 0400, 0, 0421, 0412, 0400,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0412, 0412, 0, 0, 0412, 0412, 0, 0421, 0, 0421, 0124, 020, 0124, 020, 0, 0421, 0412, 0400, 0124, 020, 0, 0,
	0, 0, 0142, 0142, 0, 0, 0142, 0142, 0, 0, 02, 02, 0, 0, 02, 02, 0, 0421, 0142, 0, 0124, 020, 0100, 0, 0, 0421, 02, 0, 0124, 020, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0412, 0412, 0214, 0214, 010, 010, 0, 0421, 0, 0421, 0, 0421, 0, 0421, 0, 0421, 0412, 0400, 0214, 0, 010, 0,
	0, 0241, 0, 0241, 0, 0241, 0, 0241, 0, 0241, 0412, 0, 0214, 0200, 010, 0, 0, 01, 0, 01, 0, 01, 0, 01, 0, 01, 0412, 0, 0214, 0, 010, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0412, 0412, 0214, 0214, 010, 010, 0, 0421, 0, 0421, 0124, 020, 0124, 020, 0, 0421, 0412, 0400, 04, 0, 0, 0,
	0, 0241, 0142, 040, 0, 0241, 0142, 040, 0, 0241, 02, 0, 0214, 0200, 0, 0, 0, 01, 0142, 0, 0124, 0, 0100, 0, 0, 01, 02, 0, 04, 0, 0, 0,
	};

static const int TblRowUniq[512] = {	// 1 is row not defined in block  mode  1 to 111
	7, 6, 6, 6, 6, 6, 6, 6, 5, 4, 4, 4, 4, 4, 4, 4, 5, 4, 4, 4, 4, 4, 4, 4, 5, 4, 4, 4, 4, 4, 4, 4,
	5, 4, 4, 4, 4, 4, 4, 4, 5, 4, 4, 4, 4, 4, 4, 4, 5, 4, 4, 4, 4, 4, 4, 4, 5, 4, 4, 4, 4, 4, 4, 4,
	3, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
	1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
	3, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
	1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
	3, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
	1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
	3, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
	1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
	3, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
	1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
	3, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
	1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
	3, 2, 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
	1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
	};

static const int TblColumnSingle[512] = {	// single in column applied to shrinked bloc
	00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
	00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
	00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
	00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
	00, 00, 00, 00, 00, 00, 00, 00, 00, 0777, 0777, 0666, 0777, 0666, 0666, 0666,
	00, 0777, 0777, 0666, 0777, 0666, 0666, 0666, 00, 0555, 0555, 0444, 0555, 0444, 0444, 0444,
	00, 0777, 0777, 0666, 0777, 0666, 0666, 0666, 00, 0555, 0555, 0444, 0555, 0444, 0444, 0444,
	00, 0555, 0555, 0444, 0555, 0444, 0444, 0444, 00, 0555, 0555, 0444, 0555, 0444, 0444, 0444,
	00, 00, 00, 00, 00, 00, 00, 00, 00, 0777, 0777, 0666, 0777, 0666, 0666, 0666,
	00, 0777, 0777, 0666, 0777, 0666, 0666, 0666, 00, 0555, 0555, 0444, 0555, 0444, 0444, 0444,
	00, 0777, 0777, 0666, 0777, 0666, 0666, 0666, 00, 0555, 0555, 0444, 0555, 0444, 0444, 0444,
	00, 0555, 0555, 0444, 0555, 0444, 0444, 0444, 00, 0555, 0555, 0444, 0555, 0444, 0444, 0444,
	00, 00, 00, 00, 00, 00, 00, 00, 00, 0333, 0333, 0222, 0333, 0222, 0222, 0222,
	00, 0333, 0333, 0222, 0333, 0222, 0222, 0222, 00, 0111, 0111, 00, 0111, 00, 00, 00,
	00, 0333, 0333, 0222, 0333, 0222, 0222, 0222, 00, 0111, 0111, 00, 0111, 00, 00, 00,
	00, 0111, 0111, 00, 0111, 00, 00, 00, 00, 0111, 0111, 00, 0111, 00, 00, 00,
	00, 00, 00, 00, 00, 00, 00, 00, 00, 0777, 0777, 0666, 0777, 0666, 0666, 0666,
	00, 0777, 0777, 0666, 0777, 0666, 0666, 0666, 00, 0555, 0555, 0444, 0555, 0444, 0444, 0444,
	00, 0777, 0777, 0666, 0777, 0666, 0666, 0666, 00, 0555, 0555, 0444, 0555, 0444, 0444, 0444,
	00, 0555, 0555, 0444, 0555, 0444, 0444, 0444, 00, 0555, 0555, 0444, 0555, 0444, 0444, 0444,
	00, 00, 00, 00, 00, 00, 00, 00, 00, 0333, 0333, 0222, 0333, 0222, 0222, 0222,
	00, 0333, 0333, 0222, 0333, 0222, 0222, 0222, 00, 0111, 0111, 00, 0111, 00, 00, 00,
	00, 0333, 0333, 0222, 0333, 0222, 0222, 0222, 00, 0111, 0111, 00, 0111, 00, 00, 00,
	00, 0111, 0111, 00, 0111, 00, 00, 00, 00, 0111, 0111, 00, 0111, 00, 00, 00,
	00, 00, 00, 00, 00, 00, 00, 00, 00, 0333, 0333, 0222, 0333, 0222, 0222, 0222,
	00, 0333, 0333, 0222, 0333, 0222, 0222, 0222, 00, 0111, 0111, 00, 0111, 00, 00, 00,
	00, 0333, 0333, 0222, 0333, 0222, 0222, 0222, 00, 0111, 0111, 00, 0111, 00, 00, 00,
	00, 0111, 0111, 00, 0111, 00, 00, 00, 00, 0111, 0111, 00, 0111, 00, 00, 00,
	00, 00, 00, 00, 00, 00, 00, 00, 00, 0333, 0333, 0222, 0333, 0222, 0222, 0222,
	00, 0333, 0333, 0222, 0333, 0222, 0222, 0222, 00, 0111, 0111, 00, 0111, 00, 00, 00,
	00, 0333, 0333, 0222, 0333, 0222, 0222, 0222, 00, 0111, 0111, 00, 0111, 00, 00, 00,
	00, 0111, 0111, 00, 0111, 00, 00, 00, 00, 0111, 0111, 00, 0111, 00, 00, 00,
	};

static const unsigned int TblRowMask[8] = {	// rows where single  found  000 to 111
	0777777777, 0777777000, 0777000777, 0777000000, 0777777, 0777000, 0777, 00, };

static const int cellToSubBand[81] = {
	0,	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,	0,
	0,	0,	0,	0,	0,	0,	0,	0,	0,
	1,	1,	1,	1,	1,	1,	1,	1,	1,
	1,	1,	1,	1,	1,	1,	1,	1,	1,
	1,	1,	1,	1,	1,	1,	1,	1,	1,
	2,	2,	2,	2,	2,	2,	2,	2,	2,
	2,	2,	2,	2,	2,	2,	2,	2,	2,
	2,	2,	2,	2,	2,	2,	2,	2,	2,
	};

static const unsigned int cellToMask[81] = {
	0x1,	0x2,	0x4,	0x8,	0x10,	0x20,	0x40,	0x80,	0x100,
	0x200,	0x400,	0x800,	0x1000,	0x2000,	0x4000,	0x8000,	0x10000,	0x20000,
	0x40000,	0x80000,	0x100000,	0x200000,	0x400000,	0x800000,	0x1000000,	0x2000000,	0x4000000,
	0x1,	0x2,	0x4,	0x8,	0x10,	0x20,	0x40,	0x80,	0x100,
	0x200,	0x400,	0x800,	0x1000,	0x2000,	0x4000,	0x8000,	0x10000,	0x20000,
	0x40000,	0x80000,	0x100000,	0x200000,	0x400000,	0x800000,	0x1000000,	0x2000000,	0x4000000,
	0x1,	0x2,	0x4,	0x8,	0x10,	0x20,	0x40,	0x80,	0x100,
	0x200,	0x400,	0x800,	0x1000,	0x2000,	0x4000,	0x8000,	0x10000,	0x20000,
	0x40000,	0x80000,	0x100000,	0x200000,	0x400000,	0x800000,	0x1000000,	0x2000000,	0x4000000,
	};

static const int digitToBaseBand[9] = {
	0,	3,	6,	9,	12,	15,	18,	21,	24,
	};

static const unsigned int TblSelfMask[81] = {
	0x37E3F001,	0x37E3F002,	0x37E3F004,	0x371F8E08,	0x371F8E10,	0x371F8E20,	0x30FC7E40,	0x30FC7E80,
	0x30FC7F00,	0x2FE003F8,	0x2FE005F8,	0x2FE009F8,	0x2F1C11C7,	0x2F1C21C7,	0x2F1C41C7,	0x28FC803F,
	0x28FD003F,	0x28FE003F,	0x1807F1F8,	0x180BF1F8,	0x1813F1F8,	0x18238FC7,	0x18438FC7,	0x18838FC7,
	0x19007E3F,	0x1A007E3F,	0x1C007E3F,	0x37E3F001,	0x37E3F002,	0x37E3F004,	0x371F8E08,	0x371F8E10,
	0x371F8E20,	0x30FC7E40,	0x30FC7E80,	0x30FC7F00,	0x2FE003F8,	0x2FE005F8,	0x2FE009F8,	0x2F1C11C7,
	0x2F1C21C7,	0x2F1C41C7,	0x28FC803F,	0x28FD003F,	0x28FE003F,	0x1807F1F8,	0x180BF1F8,	0x1813F1F8,
	0x18238FC7,	0x18438FC7,	0x18838FC7,	0x19007E3F,	0x1A007E3F,	0x1C007E3F,	0x37E3F001,	0x37E3F002,
	0x37E3F004,	0x371F8E08,	0x371F8E10,	0x371F8E20,	0x30FC7E40,	0x30FC7E80,	0x30FC7F00,	0x2FE003F8,
	0x2FE005F8,	0x2FE009F8,	0x2F1C11C7,	0x2F1C21C7,	0x2F1C41C7,	0x28FC803F,	0x28FD003F,	0x28FE003F,
	0x1807F1F8,	0x180BF1F8,	0x1813F1F8,	0x18238FC7,	0x18438FC7,	0x18838FC7,	0x19007E3F,	0x1A007E3F,
	0x1C007E3F,
	};

static const int TblAnother1[27] = {
	0x1,	0x0,	0x0,	0x4,	0x3,	0x3,	0x7,	0x6,
	0x6,	0xA,	0x9,	0x9,	0xD,	0xC,	0xC,	0x10,
	0xF,	0xF,	0x13,	0x12,	0x12,	0x16,	0x15,	0x15,
	0x19,	0x18,	0x18,
	};

static const int TblAnother2[27] = {
	0x2,	0x2,	0x1,	0x5,	0x5,	0x4,	0x8,	0x8,
	0x7,	0xB,	0xB,	0xA,	0xE,	0xE,	0xD,	0x11,
	0x11,	0x10,	0x14,	0x14,	0x13,	0x17,	0x17,	0x16,
	0x1A,	0x1A,	0x19,
	};

static const unsigned int TblOtherMask[81] = {
	0x3FFBFDFE,	0x3FF7FBFD,	0x3FEFF7FB,	0x3FDFEFF7,	0x3FBFDFEF,	0x3F7FBFDF,	0x3EFF7FBF,	0x3DFEFF7F,
	0x3BFDFEFF,	0x3FFBFDFE,	0x3FF7FBFD,	0x3FEFF7FB,	0x3FDFEFF7,	0x3FBFDFEF,	0x3F7FBFDF,	0x3EFF7FBF,
	0x3DFEFF7F,	0x3BFDFEFF,	0x3FFBFDFE,	0x3FF7FBFD,	0x3FEFF7FB,	0x3FDFEFF7,	0x3FBFDFEF,	0x3F7FBFDF,
	0x3EFF7FBF,	0x3DFEFF7F,	0x3BFDFEFF,	0x3FFBFDFE,	0x3FF7FBFD,	0x3FEFF7FB,	0x3FDFEFF7,	0x3FBFDFEF,
	0x3F7FBFDF,	0x3EFF7FBF,	0x3DFEFF7F,	0x3BFDFEFF,	0x3FFBFDFE,	0x3FF7FBFD,	0x3FEFF7FB,	0x3FDFEFF7,
	0x3FBFDFEF,	0x3F7FBFDF,	0x3EFF7FBF,	0x3DFEFF7F,	0x3BFDFEFF,	0x3FFBFDFE,	0x3FF7FBFD,	0x3FEFF7FB,
	0x3FDFEFF7,	0x3FBFDFEF,	0x3F7FBFDF,	0x3EFF7FBF,	0x3DFEFF7F,	0x3BFDFEFF,	0x3FFBFDFE,	0x3FF7FBFD,
	0x3FEFF7FB,	0x3FDFEFF7,	0x3FBFDFEF,	0x3F7FBFDF,	0x3EFF7FBF,	0x3DFEFF7F,	0x3BFDFEFF,	0x3FFBFDFE,
	0x3FF7FBFD,	0x3FEFF7FB,	0x3FDFEFF7,	0x3FBFDFEF,	0x3F7FBFDF,	0x3EFF7FBF,	0x3DFEFF7F,	0x3BFDFEFF,
	0x3FFBFDFE,	0x3FF7FBFD,	0x3FEFF7FB,	0x3FDFEFF7,	0x3FBFDFEF,	0x3F7FBFDF,	0x3EFF7FBF,	0x3DFEFF7F,
	0x3BFDFEFF,
	};

static const int cellToRow[81] = {				// ??? unused ???
	0,	0,	0,	0,	0,	0,	0,	0,	0,
	1,	1,	1,	1,	1,	1,	1,	1,	1,
	2,	2,	2,	2,	2,	2,	2,	2,	2,
	3,	3,	3,	3,	3,	3,	3,	3,	3,
	4,	4,	4,	4,	4,	4,	4,	4,	4,
	5,	5,	5,	5,	5,	5,	5,	5,	5,
	6,	6,	6,	6,	6,	6,	6,	6,	6,
	7,	7,	7,	7,	7,	7,	7,	7,	7,
	8,	8,	8,	8,	8,	8,	8,	8,	8,
	};

static const int mod3[27] = {
	0,	1,	2,	0,	1,	2,	0,	1,	2,
	0,	1,	2,	0,	1,	2,	0,	1,	2,
	0,	1,	2,	0,	1,	2,	0,	1,	2,
	};

static const int mod27[81] = {
	0,	1,	2,	3,	4,	5,	6,	7,	8,
	9,	10,	11,	12,	13,	14,	15,	16,	17,
	18,	19,	20,	21,	22,	23,	24,	25,	26,
	0,	1,	2,	3,	4,	5,	6,	7,	8,
	9,	10,	11,	12,	13,	14,	15,	16,	17,
	18,	19,	20,	21,	22,	23,	24,	25,	26,
	0,	1,	2,	3,	4,	5,	6,	7,	8,
	9,	10,	11,	12,	13,	14,	15,	16,	17,
	18,	19,	20,	21,	22,	23,	24,	25,	26,
	};

static const int MultiplyDeBruijnBitPosition32[32] = {
	0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
	31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
	};
#define BitPos(map)		MultiplyDeBruijnBitPosition32[((unsigned int)(map*0x077CB531U))>>27]

static int FullUpdate(void);
static void Guess(void);

static int
SetSolvedDigit(int cell,int digit)					// Set a cell as solved - used in InitSudoku
{
	int subBand = cellToSubBand[cell];
	int band = digitToBaseBand[digit] + subBand;
	unsigned mask = cellToMask[cell];
	if (!(g->bands[band]&mask)) return(0);
	g->bands[band] &= TblSelfMask[cell];
	unsigned int tblMask = TblOtherMask[cell];
	g->bands[TblAnother1[band]] &= tblMask;
	g->bands[TblAnother2[band]] &= tblMask;
	mask = ~mask;
	g->unsolvedCells[subBand] &= mask;
	int rowBit = digit*9+cellToRow[cell];
	g->unsolvedRows[rowBit/27] &= ~(1<<(mod27[rowBit]));
	g->bands[subBand]&=mask;
	g->bands[subBand+3]&=mask;
	g->bands[subBand+6]&=mask;
	g->bands[subBand+9]&=mask;
	g->bands[subBand+12]&=mask;
	g->bands[subBand+15]&=mask;
	g->bands[subBand+18]&=mask;
	g->bands[subBand+21]&=mask;
	g->bands[subBand+24]&=mask;
	g->bands[band] |= ~mask;
	return(1);
	}

static int
SetSolvedMask(int band,unsigned int mask)			// Set a cell as solved - used in various guess routines
{
	if (!(g->bands[band]&mask)) return(0);
	int subBand = mod3[band];
	int cell=subBand*27+BitPos(mask);
	g->bands[band] &= TblSelfMask[cell];
#if 0
	g->bands[TblAnother1[band]] &= TblOtherMask[cell];
	g->bands[TblAnother2[band]] &= TblOtherMask[cell];
	mask = ~mask;
	g->unsolvedCells[subBand] &= mask;
	int rowBit = (band/3)*9+cellToRow[cell];
	g->unsolvedRows[rowBit/27] &= ~(1<<(mod27[rowBit]));
	for (int indx=subBand; indx<27; indx+=3) {
		if (indx==band) continue;
		g->bands[indx]&=mask;
		}
#endif
	return(1);
	}

static int
InitSudoku(const char *board)						// Setup everything and load the puzzle
{
	g = stack;
	numSolutions=0;
	for (int band=0; band<3*9; ++band) g->bands[band]=BIT_SET_27;
	memset(g->prevBands,0,sizeof(g->prevBands));
	g->unsolvedCells[0]=g->unsolvedCells[1]=g->unsolvedCells[2]=BIT_SET_27;
	g->unsolvedRows[0]=g->unsolvedRows[1]=g->unsolvedRows[2]=BIT_SET_27;
	g->pairs[0]=g->pairs[1]=g->pairs[2]=0;
	for (int cell=0; cell<81; ++cell,++board) {
		if (isdigit(*board) && *board!='0') {
			int digit = *board-'1';
			if (!SetSolvedDigit(cell,digit)) return(0);
			}
		else if (!*board) return(0);								// End of string before end of puzzle!
		}
	return(1);
	}

//
//	The core Update routine from zhouyundong
//	This copy has been optimized by champagne and JasonLion in minor ways
//

#define UPDN(I,J,K,L) \
	A=g->bands[I*3+J]; \
	Shrink = (TblShrinkMask[A & 0x1FF] | TblShrinkMask[(A>>9) & 0x1FF]<<3 | TblShrinkMask[(A>>18)]<<6); \
	if ((A &=TblComplexMask[Shrink])==0)  return(0); \
	B=g->bands[I*3+K]; \
	C=g->bands[I*3+L]; \
	S = ((A | (A>>9) | (A>>18)) & 0x1FF); \
	g->bands[I*3+L] &= TblMaskSingle[S] ;/* & TblMaskDouble[S | ((B | (B>>9) | (B>>18)) & 0x1FF)]; */\
	g->bands[I*3+K] &= TblMaskSingle[S] ;/* & TblMaskDouble[S | ((C | (C>>9) | (C>>18)) & 0x1FF)]; */\
	S = TblRowUniq[TblShrinkSingle[Shrink] & TblColumnSingle[S]]; \
	g->prevBands[I*3+J] = g->bands[I*3+J] = A;

#define UPWCL(I,P,Q,R,T,U,V,W,X) \
	cl = ~(A & TblRowMask[S]); \
	g->unsolvedCells[I] &= cl; \
	g->bands[P]&= cl; \
	g->bands[Q]&= cl; \
	g->bands[R]&= cl; \
	g->bands[T]&= cl; \
	g->bands[U]&= cl; \
	g->bands[V]&= cl; \
	g->bands[W]&= cl; \
	g->bands[X]&= cl;

static int
Update()											// Core of fast processing - by zhouyundong
{
	register unsigned int Shrink = 1, S, A, B, C, cl;
	while (Shrink) {
		Shrink = 0;
		if (!g->unsolvedRows[0]) goto digit3;
		{
			register unsigned int  AR = g->unsolvedRows[0];	// valid for digits 0,1,2
			if (!(AR & 0x1ff)) goto digit1;
			if (g->bands[0*3+0] == g->prevBands[0*3+0]) goto digit0b;
			UPDN(0, 0, 1, 2);
			if ((AR & 7) != S) {
				AR &= 0777777770 | S;
				UPWCL(0, 3, 6, 9, 12, 15, 18, 21, 24);
				}
digit0b:
			if (g->bands[0*3+1] == g->prevBands[0*3+1]) goto digit0c;
			UPDN(0, 1, 0, 2);
			if (((AR>>3) & 7) != S) {
				AR &= 0777777707 | (S<<3);
				UPWCL(1, 4, 7, 10, 13, 16, 19, 22, 25);
				}
digit0c:
			if (g->bands[0*3+2] == g->prevBands[0*3+2]) goto digit1;
			UPDN(0, 2, 0, 1);
			if (((AR>>6) & 7) != S) {
				AR &= 0777777077 | (S<<6);
				UPWCL(2, 5, 8, 11, 14, 17, 20, 23, 26);
				}
digit1:
			if (!((AR>>9) & 0x1ff)) goto digit2;
			if (g->bands[1*3+0] == g->prevBands[1*3+0]) goto digit1b;
			UPDN(1, 0, 1, 2);
			if (((AR>>9) & 7) != S) {
				AR &= 0777770777 | (S<<9);
				UPWCL(0, 0, 6, 9, 12, 15, 18, 21, 24);
				}
digit1b:
			if (g->bands[1*3+1] == g->prevBands[1*3+1]) goto digit1c;
			UPDN(1, 1, 0, 2);
			if (((AR>>12) & 7) != S) {
				AR &= 0777707777 | (S<<12);
				UPWCL(1, 1, 7, 10, 13, 16, 19, 22, 25);
				}
digit1c:
			if (g->bands[1*3+2] == g->prevBands[1*3+2]) goto digit2;
			UPDN(1, 2, 0, 1);
			if (((AR>>15) & 7) != S) {
				AR &= 0777077777 | (S<<15);
				UPWCL(2, 2, 8, 11, 14, 17, 20, 23, 26);
				}
digit2:
			if (!((AR>>18) & 0x1ff)) goto end012;
			if (g->bands[2*3+0] == g->prevBands[2*3+0]) goto digit2b;
			UPDN(2, 0, 1, 2);
			if (((AR>>18) & 7) != S) {
				AR &= 0770777777 | (S<<18);
				UPWCL(0, 0, 3, 9, 12, 15, 18, 21, 24);
				}
digit2b:
			if (g->bands[2*3+1] == g->prevBands[2*3+1]) goto digit2c;
			UPDN(2, 1, 0, 2);
			if (((AR>>21) & 7) != S) {
				AR &= 0707777777 | (S<<21);
				UPWCL(1, 1, 4, 10, 13, 16, 19, 22, 25);
				}
digit2c:
			if (g->bands[2*3+2] == g->prevBands[2*3+2]) goto end012;
			UPDN(2, 2, 0, 1)if (((AR>>24) & 7) != S) {
				AR &= 0077777777 | (S<<24);
				UPWCL(2, 2, 5, 11, 14, 17, 20, 23, 26);
				}
end012:
			g->unsolvedRows[0] = AR;
			}	// end of validity for AR
digit3:
		if (!g->unsolvedRows[1]) goto digit6;
		{
			register unsigned int  AR = g->unsolvedRows[1];	// valid for digits 3,4,5
			if (!(AR & 0x1ff)) goto digit4;
			if (g->bands[3*3+0] == g->prevBands[3*3+0]) goto digit3b;
			UPDN(3, 0, 1, 2);
			if ((AR & 7) != S) {
				AR &= 0777777770 | S;
				UPWCL(0, 0, 3, 6, 12, 15, 18, 21, 24);
				}
digit3b:
			if (g->bands[3*3+1] == g->prevBands[3*3+1]) goto digit3c;
			UPDN(3, 1, 0, 2);
			if (((AR>>3) & 7) != S) {
				AR &= 0777777707 | (S<<3);
				UPWCL(1, 1, 4, 7, 13, 16, 19, 22, 25);
				}
digit3c:
			if (g->bands[3*3+2] == g->prevBands[3*3+2]) goto digit4;
			UPDN(3, 2, 0, 1);
			if (((AR>>6) & 7) != S) {
				AR &= 0777777077 | (S<<6);
				UPWCL(2, 2, 5, 8, 14, 17, 20, 23, 26);
				}
digit4:
			if (!((AR>>9) & 0x1ff)) goto digit5;
			if (g->bands[4*3+0] == g->prevBands[4*3+0]) goto digit4b;
			UPDN(4, 0, 1, 2);
			if (((AR>>9) & 7) != S) {
				AR &= 0777770777 | (S<<9);
				UPWCL(0, 0, 3, 6, 9, 15, 18, 21, 24);
				}
digit4b:
			if (g->bands[4*3+1] == g->prevBands[4*3+1]) goto digit4c;
			UPDN(4, 1, 0, 2);
			if (((AR>>12) & 7) != S) {
				AR &= 0777707777 | (S<<12);
				UPWCL(1, 1, 4, 7, 10, 16, 19, 22, 25);
				}
digit4c:
			if (g->bands[4*3+2] == g->prevBands[4*3+2]) goto digit5;
			UPDN(4, 2, 0, 1);
			if (((AR>>15) & 7) != S) {
				AR &= 0777077777 | (S<<15);
				UPWCL(2, 2, 5, 8, 11, 17, 20, 23, 26);
				}
digit5:
			if (!((AR>>18) & 0x1ff)) goto end345;
			if (g->bands[5*3+0] == g->prevBands[5*3+0]) goto digit5b;
			UPDN(5, 0, 1, 2);
			if (((AR>>18) & 7) != S) {
				AR &= 0770777777 | (S<<18);
				UPWCL(0, 0, 3, 6, 9, 12, 18, 21, 24);
				}
digit5b:
			if (g->bands[5*3+1] == g->prevBands[5*3+1]) goto digit5c;
			UPDN(5, 1, 0, 2);
			if (((AR>>21) & 7) != S) {
				AR &= 0707777777 | (S<<21);
				UPWCL(1, 1, 4, 7, 10, 13, 19, 22, 25);
				}
digit5c:
			if (g->bands[5*3+2] == g->prevBands[5*3+2]) goto end345;
			UPDN(5, 2, 0, 1);
			if (((AR>>24) & 7) != S) {
				AR &= 0077777777 | (S<<24);
				UPWCL(2, 2, 5, 8, 11, 14, 20, 23, 26);
				}
end345:
			g->unsolvedRows[1] = AR;
			}	// end of validity for AR
digit6:
		if (!g->unsolvedRows[2]) continue;
		{
			register unsigned int  AR = g->unsolvedRows[2];	// valid for digits 6,7,8
			if (!(AR & 0x1ff)) goto digit7;
			if (g->bands[6*3+0] == g->prevBands[6*3+0]) goto digit6b;
			UPDN(6, 0, 1, 2);
			if ((AR & 7) != S) {
				AR &= 0777777770 | S;
				UPWCL(0, 0, 3, 6, 9, 12, 15, 21, 24);
				}
digit6b:
			if (g->bands[6*3+1] == g->prevBands[6*3+1]) goto digit6c;
			UPDN(6, 1, 0, 2);
			if (((AR>>3) & 7) != S) {
				AR &= 0777777707 | (S<<3);
				UPWCL(1, 1, 4, 7, 10, 13, 16, 22, 25);
				}
digit6c:
			if (g->bands[6*3+2] == g->prevBands[6*3+2]) goto digit7;
			UPDN(6, 2, 0, 1);
			if (((AR>>6) & 7) != S) {
				AR &= 0777777077 | (S<<6);
				UPWCL(2, 2, 5, 8, 11, 14, 17, 23, 26);
				}
digit7:
			if (!((AR>>9) & 0x1ff)) goto digit8;
			if (g->bands[7*3+0] == g->prevBands[7*3+0]) goto digit7b;
			UPDN(7, 0, 1, 2);
			if (((AR>>9) & 7) != S) {
				AR &= 0777770777 | (S<<9);
				UPWCL(0, 0, 3, 6, 9, 12, 15, 18, 24);
				}
digit7b:
			if (g->bands[7*3+1] == g->prevBands[7*3+1]) goto digit7c;
			UPDN(7, 1, 0, 2);
			if (((AR>>12) & 7) != S) {
				AR &= 0777707777 | (S<<12);
				UPWCL(1, 1, 4, 7, 10, 13, 16, 19, 25);
				}
digit7c:
			if (g->bands[7*3+2] == g->prevBands[7*3+2]) goto digit8;
			UPDN(7, 2, 0, 1);
			if (((AR>>15) & 7) != S) {
				AR &= 0777077777 | (S<<15);
				UPWCL(2, 2, 5, 8, 11, 14, 17, 20, 26);
				}
digit8:
			if (!((AR>>18) & 0x1ff)) goto end678;
			if (g->bands[8*3+0] == g->prevBands[8*3+0]) goto digit8b;
			UPDN(8, 0, 1, 2);
			if (((AR>>18) & 7) != S) {
				AR &= 0770777777 | (S<<18);
				UPWCL(0, 0, 3, 6, 9, 12, 15, 18, 21);
				}
digit8b:
			if (g->bands[8*3+1] == g->prevBands[8*3+1]) goto digit8c;
			UPDN(8, 1, 0, 2);
			if (((AR>>21) & 7) != S) {
				AR &= 0707777777 | (S<<21);
				UPWCL(1, 1, 4, 7, 10, 13, 16, 19, 22);
				}
digit8c:
			if (g->bands[8*3+2] == g->prevBands[8*3+2]) goto end678;
			UPDN(8, 2, 0, 1);
			if (((AR>>24) & 7) != S) {
				AR &= 0077777777 | (S<<24);
				UPWCL(2, 2, 5, 8, 11, 14, 17, 20, 23);
				}
end678:
			g->unsolvedRows[2] = AR;
			}	// end of validity for AR
		}	// end while
	return 1;
	}

static int
ApplySingleOrEmptyCells(void)						// Find singles, bi-value cells, and impossible cells
{
	singleApplied=0;
	for (int subBand=0; subBand<3; ++subBand) {
#if 0
		unsigned int R1 = 0, R2 = 0, R3 = 0;
		for (int band=subBand; band<27; band+=3) {
			unsigned int bandData = g->bands[band];
			R3 |= R2&bandData;
			R2 |= R1&bandData;
			R1 |= bandData;
			}
#else
															// Loop unrolling _really_ helps
		unsigned int R1 = g->bands[subBand];				// R1 - Cells in band with pencil one or more times
		unsigned int bandData = g->bands[subBand+3];		// bandData - hint to save value in register
		unsigned int R2 = R1 & bandData;					// R2 - pencil mark in cell two or more times
		R1|=bandData;
		bandData = g->bands[subBand+6];
		unsigned int R3 = R2 & bandData;					// R3 - pencil mark in cell three or more times
		R2 |= R1&bandData;
		R1 |= bandData;
		bandData = g->bands[subBand+9];
		R3 |= R2&bandData;
		R2 |= R1&bandData;
		R1 |= bandData;
		bandData = g->bands[subBand+12];
		R3 |= R2&bandData;
		R2 |= R1&bandData;
		R1 |= bandData;
		bandData = g->bands[subBand+15];
		R3 |= R2&bandData;
		R2 |= R1&bandData;
		R1 |= bandData;
		bandData = g->bands[subBand+18];
		R3 |= R2&bandData;
		R2 |= R1&bandData;
		R1 |= bandData;
		bandData = g->bands[subBand+21];
		R3 |= R2&bandData;
		R2 |= R1&bandData;
		R1 |= bandData;
		bandData = g->bands[subBand+24];
		R3 |= R2&bandData;
		R2 |= R1&bandData;
		R1 |= bandData;
#endif
		if (R1!=BIT_SET_27) return(1);							// Something is locked, can't be solved
		g->pairs[subBand] = R2 & ~R3;							// Exactly two pencil marks in cell
		R1 &= ~R2;												// Exactly one pencil mark in cell
		R1 &= g->unsolvedCells[subBand];						// Ignore already solved cells
		while (R1) {											// Set all the single pencil mark cells
			singleApplied=1;
			unsigned int bit = R1 & -R1;						// Process once cell at a time
			R1^=bit;
			int digit;
			for (digit=0; digit<9; ++digit) {					// Requires finding which digit they are for
				if (g->bands[digit*3+subBand]&bit) {
					SetSolvedMask(digit*3+subBand,bit);
					break;
					}
				}
			if (digit==9) return(1);							// Previous singles locked the cell
			}
		}
	return(0);
	}

static void
ExtractSolution(char *solution)						// Extract solution as a character string
{
	for (int cell = 0; cell<81; ++cell) {
		int mask = cellToMask[cell];
		int offset = cellToSubBand[cell];
		for (int digit = 0; digit<9; ++digit) {
			if (g->bands[offset]&mask) {
				solution[cell]='1'+digit;
				break;
				}
			offset+=3;
			}
		}
	solution[81]=0;
	}

static int
GuessBiValueInCell(void)							// Try both options for cells with exactly two pencil marks
{																// Uses pairs map, set in ApplySingleOrEmptyCells
	for (int subBand=0; subBand<3; ++subBand) {
		unsigned int map = g->pairs[subBand];
		if (map) {
			map &= -map;
			int tries=2;
			int band = subBand;
			for (int digit=0; digit<9; ++digit,band+=3) {
				if (g->bands[band]&map) {
					if (--tries) {								// First of pair
						memcpy(g+1,g,sizeof(State));
						g->bands[band]^=map;
						++g;
						SetSolvedMask(band,map);
                        JCZSolve_guesses++;
						if (FullUpdate()) Guess();
						--g;
						}
					else {										// Second of pair
						SetSolvedMask(band,map);
						if (FullUpdate()) Guess();
						return(1);
						}
					}
				}
			}
		}
	return(0);
	}

static void
GuessFirstCell(void)								// Guess all possibilities in first unsolved cell
{																// Kind of dumb, but _way_ fast code
	for (int subBand=0; subBand<3; ++subBand) {
		if (!g->unsolvedCells[subBand]) continue;
		unsigned int cellMask = g->unsolvedCells[subBand];
		cellMask &= -cellMask;
		int band = subBand;
		for (int digit=0; digit<9; ++digit,band+=3) {
			if (g->bands[band]&cellMask) {
				memcpy(g+1,g,sizeof(State));					// Eliminate option in the current stack entry
				g->bands[band]^=cellMask;
				++g;
				SetSolvedMask(band,cellMask);					// and try it out in a nested stack entry
                JCZSolve_guesses++;
				if (FullUpdate()) Guess();
				--g;
				}
			}
		return;
		}
	}

static void
Guess(void)											// Either already solved, or guess and recurse
{
	if (!(g->unsolvedRows[0]|g->unsolvedRows[1]|g->unsolvedRows[2])) {	// Already solved
		if (solution && !numSolutions) ExtractSolution(solution);		// store the first solution
		numSolutions++;
		return;
		}
	if (!GuessBiValueInCell()) GuessFirstCell();				// Both of these recurse
	}

static int
FullUpdate(void)									// Get as far as possible without guessing
{
	if (numSolutions>=limitSolutions) return(0);
	while (1) {
		if (!Update()) return(0);							// game locked in update
		if (!(g->unsolvedCells[0]|g->unsolvedCells[1]|g->unsolvedCells[2])) return(2);
		if (ApplySingleOrEmptyCells()) return(0);			// locked empty cell or conflict singles in cells
		if (singleApplied) continue;						// Found a single, run Update again
		break;
		}
	return(1);
	}

// uniform interface

extern int							// Calculate the number of solutions - standardized interface
JCZSolver(const char *puzzle,char *solutionPtr,int limit)
{
	numSolutions=0;
	limitSolutions=limit;
	solution=solutionPtr;
	if (!InitSudoku(puzzle)) return(0);						// locked invalid cell
	if (ApplySingleOrEmptyCells()) return(0);				// locked empty cell or conflict singles in cells
	if (!FullUpdate()) return(0);
	Guess();
	return(numSolutions);
	}

// END OF JCZSolve.c
